package com.haibara.codesubmiteval.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haibara.codesubmiteval.common.DeleteRequest;
import com.haibara.codesubmiteval.common.ErrorCode;
import com.haibara.codesubmiteval.constant.CommonConstant;
import com.haibara.codesubmiteval.constant.FileConstant;
import com.haibara.codesubmiteval.exception.ThrowUtils;
import com.haibara.codesubmiteval.mapper.QuestionCaseMapper;
import com.haibara.codesubmiteval.model.dto.questionCase.QuestionCaseAddRequest;
import com.haibara.codesubmiteval.model.dto.questionCase.QuestionCaseEditRequest;
import com.haibara.codesubmiteval.model.dto.questionCase.QuestionCaseQueryRequest;
import com.haibara.codesubmiteval.model.entity.QuestionCase;
import com.haibara.codesubmiteval.service.QuestionCaseService;
import com.haibara.codesubmiteval.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: mengyu
 * @Date: 2025/2/1
 */
@Service
@Slf4j
public class QuestionCaseServiceImpl extends ServiceImpl<QuestionCaseMapper, QuestionCase> implements QuestionCaseService {

    @Override
    public List<QuestionCase> getQuestionCase(Long id) {
        LambdaQueryWrapper<QuestionCase> questionCaseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionCaseLambdaQueryWrapper.eq(id != null, QuestionCase::getQuestionId, id);
        return this.baseMapper.selectList(questionCaseLambdaQueryWrapper);
    }

    @Override
public Page<QuestionCase> pageQuestionCase(QuestionCaseQueryRequest questionCaseQueryRequest) {
        Long questionId = questionCaseQueryRequest.getQuestionId();
        Long id = questionCaseQueryRequest.getId();
        long current = questionCaseQueryRequest.getCurrent();
        long pageSize = questionCaseQueryRequest.getPageSize();
        String sortField = questionCaseQueryRequest.getSortField();
        String sortOrder = questionCaseQueryRequest.getSortOrder();
        // 构建查询条件
        LambdaQueryWrapper<QuestionCase> lqw = new LambdaQueryWrapper<>();
        // 过滤
        lqw.eq(questionId != null, QuestionCase::getQuestionId, questionId)
                .eq(id != null, QuestionCase::getId, id);
        // 分页
        if (!StrUtil.isBlankIfStr(sortField)) {
            lqw.orderBy("createTime".equals(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), QuestionCase::getCreateTime);
            lqw.orderBy("updateTime".equals(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), QuestionCase::getUpdateTime);
            lqw.orderBy("id".equals(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), QuestionCase::getId);
        }
        return this.page(new Page<>(current, pageSize), lqw);
    }

    @Override
    public void addQuestionCase(QuestionCaseAddRequest questionCaseAddRequest) {
        Long questionId = questionCaseAddRequest.getQuestionId();
        List<String> argumentsInput = questionCaseAddRequest.getArgumentsInput();
        List<String> fileInput = questionCaseAddRequest.getFileInput();
        String output = questionCaseAddRequest.getOutput();
        String fileOutput = questionCaseAddRequest.getFileOutput();
        QuestionCase questionCase = new QuestionCase();
        questionCase.setQuestionId(questionId);
        questionCase.setArgumentsInput(JSONUtil.toJsonStr(argumentsInput));
        if (fileInput == null || fileInput.isEmpty()) {
            questionCase.setFileInput("[]");
        } else {
            questionCase.setFileInput(JSONUtil.toJsonStr(fileInput));
        }
        if (fileOutput == null || StrUtil.isBlankIfStr(fileOutput)) {
            questionCase.setFileOutput("");
        } else {
            questionCase.setFileOutput(fileOutput);
        }
        if (output == null || StrUtil.isBlankIfStr(output)) {
            questionCase.setOutput("");
        } else {
            questionCase.setOutput(output);
        }
        int insert = this.baseMapper.insert(questionCase);
        ThrowUtils.throwIf(insert != 1, ErrorCode.SYSTEM_ERROR, "新增测试用例失败");
        // 判断是否需要进行文件移动 -> 如果fileInput为空则不需要
        if (fileInput != null && !fileInput.isEmpty()) {
            // 移动文件的目的地文件夹
            String moveToDir = FileConstant.getInputFilePath(questionId, questionCase.getId());
            // 移动文件
            try {
                FileUtil.moveFileTo(FileConstant.tempFilePath, fileInput, moveToDir);
            } catch (Exception e) {
                this.baseMapper.deleteById(questionCase.getId());
                try {
                    FileUtil.clearDirectory(moveToDir);
                } catch (IOException ex) {
                    throw new RuntimeException("清空文件夹失败 : " + moveToDir);
                }
                throw new RuntimeException(e);
            }
            // 设置只读权限
            for (String filename : fileInput) {
                String filepath = FileConstant.getInputFilePath(questionId, questionCase.getId(), filename);
                FileUtil.setFilePermissions(filepath, FileUtil.getAllReadPermission());
            }
        }
        // 移动fileOutput
        if (fileOutput != null && !StrUtil.isBlankIfStr(fileOutput)) {
            String moveToDir = FileConstant.getOutputFilePath(questionId, questionCase.getId());
            // 移动文件
            try {
                FileUtil.moveFileTo(FileConstant.tempFilePath, fileOutput, moveToDir);
            } catch (Exception e) {
                this.baseMapper.deleteById(questionCase.getId());
                try {
                    FileUtil.clearDirectory(moveToDir);
                } catch (IOException ex) {
                    throw new RuntimeException("清空文件夹失败 : " + moveToDir);
                }
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    @Transactional
    public void updateQuestionCase(QuestionCaseEditRequest questionCaseEditRequest) {
        Long id = questionCaseEditRequest.getId();
        List<String> argumentsInput = questionCaseEditRequest.getArgumentsInput();
        List<String> fileInput = questionCaseEditRequest.getFileInput();
        if (fileInput == null) {
            fileInput = new ArrayList<>();
        }
        String output = questionCaseEditRequest.getOutput();
        String fileOutput = questionCaseEditRequest.getFileOutput();
        if (fileOutput == null) {
            fileOutput = "";
        }
        QuestionCase originQuestionCase = this.baseMapper.selectById(id);
        String originQuestionCaseFileOutput = originQuestionCase.getFileOutput();
        String originQuestionCaseFileInput = originQuestionCase.getFileInput();
        // 原测试用例的文件输入
        List<String> originFiles = JSONUtil.toList(originQuestionCaseFileInput, String.class);
        // 进行数据库修改
        QuestionCase questionCase = new QuestionCase();
        questionCase.setId(id);
        questionCase.setArgumentsInput(JSONUtil.toJsonStr(argumentsInput));
        questionCase.setFileInput(JSONUtil.toJsonStr(fileInput));
        questionCase.setOutput(output);
        questionCase.setFileOutput(fileOutput);
        int i = this.baseMapper.updateById(questionCase);
        ThrowUtils.throwIf(i != 1, ErrorCode.SYSTEM_ERROR, "修改测试用例失败 : " + id);
        // 判断原测试用例文件是否需要新增 or 删除
        // 将新文件移动到对应文件夹
        String moveToDir = FileConstant.getInputFilePath(originQuestionCase.getQuestionId(), questionCase.getId());
        List<String> movedFiles = new ArrayList<>();
        for (String s : fileInput) {
            if (!originFiles.contains(s)) {
                // 移动新文件
                try {
                    FileUtil.moveFileTo(FileConstant.tempFilePath, s, moveToDir);
                    movedFiles.add(s);
                } catch (Exception e) {
                    // 清空已转移的文件
                    for (String movedFile : movedFiles) {
                        try {
                            FileUtil.moveFileTo(moveToDir, movedFile, FileConstant.tempFilePath);
                        } catch (Exception ex) {
                            // 如果转移仍出问题，则删除该测试用例
                            this.baseMapper.deleteById(id);
                            throw new RuntimeException(ex);
                        }
                    }
                    throw new RuntimeException(e);
                }
                // 设置只读权限
                String filepath = FileConstant.getInputFilePath(originQuestionCase.getQuestionId(), questionCase.getId(), s);
                FileUtil.setFilePermissions(filepath, FileUtil.getAllReadPermission());
            }
        }
        movedFiles.clear();
        // 删除原文件夹中需要被移除的文件
        for (String originFile : originFiles) {
            if (!fileInput.contains(originFile)) {
                // 代表originFile需要删除，这里是思路是先转移至temp文件夹，如果出异常再转回来
                try {
                    FileUtil.moveFileTo(moveToDir, originFile, FileConstant.tempFilePath);
                    movedFiles.add(originFile);
                } catch (Exception e) {
                    // 出异常，还原文件
                    try {
                        FileUtil.moveFileTo(FileConstant.tempFilePath, movedFiles, moveToDir);
                    } catch (Exception ex) {
                        // 如果转移仍出问题，则删除该测试用例
                        this.baseMapper.deleteById(id);
                        throw new RuntimeException(ex);
                    }
                    throw new RuntimeException(e);
                }

            }
        }
        // 修改文件输出
        // 两个都为空代表输出文件没有更新
        moveToDir = FileConstant.getOutputFilePath(originQuestionCase.getQuestionId(), questionCase.getId());
        if (!StrUtil.isBlankIfStr(originQuestionCaseFileOutput) || !StrUtil.isBlankIfStr(fileOutput)) {
            if (!StrUtil.isBlankIfStr(originQuestionCaseFileOutput) && !StrUtil.isBlankIfStr(fileOutput)) {
                // 判断两个文件名是否相同
                if (!originQuestionCaseFileOutput.equals(fileOutput)) {
                    // 不相同代表需要更新
                    try {
                        FileUtil.moveFileTo(moveToDir, originQuestionCaseFileOutput, FileConstant.tempFilePath);
                        FileUtil.moveFileTo(FileConstant.tempFilePath, fileOutput, moveToDir);
                    } catch (Exception e) {
                        // 出异常，还原文件
                        try {
                            FileUtil.moveFileTo(FileConstant.tempFilePath, originQuestionCaseFileOutput, moveToDir);
                        } catch (Exception ex) {
                            // 如果转移仍出问题，则删除该测试用例
                            this.baseMapper.deleteById(id);
                            throw new RuntimeException(ex);
                        }
                        throw new RuntimeException(e);
                    }
                }
            } else if (StrUtil.isBlankIfStr(originQuestionCaseFileOutput)) {
                // 原输出文件为空，代表新增文件
                try {
                    FileUtil.moveFileTo(FileConstant.tempFilePath, fileOutput, moveToDir);
                } catch (Exception e) {
                    // 出异常，还原文件
                    try {
                        FileUtil.moveFileTo(moveToDir, fileOutput, FileConstant.tempFilePath);
                    } catch (Exception ex) {
                        // 如果转移仍出问题，则删除该测试用例
                        this.baseMapper.deleteById(id);
                        throw new RuntimeException(ex);
                    }
                    throw new RuntimeException(e);
                }
            } else {
                // 新输出文件为空，代表删除原输出文件
                try {
                    FileUtil.moveFileTo(moveToDir, originQuestionCaseFileOutput, FileConstant.tempFilePath);
                } catch (Exception e) {
                    // 出异常，还原文件
                    try {
                        FileUtil.moveFileTo(FileConstant.tempFilePath, originQuestionCaseFileOutput, moveToDir);
                    } catch (Exception ex) {
                        // 如果转移仍出问题，则删除该测试用例
                        this.baseMapper.deleteById(id);
                        throw new RuntimeException(ex);
                    }
                    throw new RuntimeException(e);
                }
            }

        }

    }

    @Override
    public void deleteQuestionCase(DeleteRequest deleteRequest) {
        Long id = deleteRequest.getId();
        QuestionCase questionCase = this.baseMapper.selectById(id);
        // 删除数据库记录
        this.baseMapper.deleteById(id);
        // 删除对应文件
        // input
        List<String> inputFilenames = JSONUtil.toList(questionCase.getFileInput(), String.class);
        if (inputFilenames != null && !inputFilenames.isEmpty()) {
            for (String s : inputFilenames) {
                try {
                    FileUtil.deleteFileByName(FileConstant.getInputFilePath(questionCase.getQuestionId(), questionCase.getId()), s);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // output
        String fileOutput = questionCase.getFileOutput();
        if (fileOutput != null && !StrUtil.isBlankIfStr(fileOutput)) {
            try {
                FileUtil.deleteFileByName(FileConstant.getOutputFilePath(questionCase.getQuestionId(), questionCase.getId()), fileOutput);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
